package com.xuelang.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.xuelang.pipeline.client.common.util.RedisHelper;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Redis配置：
 * - 基于 spring.redis.* 构建 LettuceConnectionFactory
 * - 定义 RedisTemplate 与 RedisHelper
 */
@Configuration
public class RedisConfig {

    private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);

    @Bean
    @Primary
    public LettuceConnectionFactory redisConnectionFactory(Environment env, RedisProperties redisProperties) {
        // 优先读取 Environment，确保从激活的 profile 取值
        String host = env.getProperty("spring.redis.host");
        Integer port = env.getProperty("spring.redis.port", Integer.class);
        String password = env.getProperty("spring.redis.password");
        Integer database = env.getProperty("spring.redis.database", Integer.class);

        if (!StringUtils.hasText(host)) {
            host = redisProperties.getHost();
        }
        if (port == null) {
            port = redisProperties.getPort();
        }
        if (!StringUtils.hasText(password)) {
            password = redisProperties.getPassword();
        }
        if (database == null) {
            database = redisProperties.getDatabase();
        }

        if (!StringUtils.hasText(host)) {
            throw new IllegalStateException("spring.redis.host is missing; please configure it in application.yml");
        }
        if (port == null) {
            port = 6379; // 合理默认
        }
        if (database == null) {
            database = 0;
        }

        log.info("Configuring Redis connection -> host: {}, port: {}, db: {}", host, port, database);

        RedisStandaloneConfiguration standalone = new RedisStandaloneConfiguration();
        standalone.setHostName(host);
        standalone.setPort(port);
        if (StringUtils.hasText(password)) {
            standalone.setPassword(RedisPassword.of(password));
        }
        standalone.setDatabase(database);

        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder().build();
        return new LettuceConnectionFactory(standalone, clientConfig);
    }

    @Bean
    public RedisHelper redisHelper() {
        return new RedisHelper();
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}